package com.atguigu.aspect;

import com.atguigu.annotations.MyRedisCache;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.Joinpoint;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import javax.swing.text.Element;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

@Component
@Aspect
@Slf4j
public class MyRedisCacheAspect {

    @Resource
    private RedisTemplate redisTemplate;

    @Pointcut("@annotation(com.atguigu.annotations.MyRedisCache)")
    public void cachePointCut() {

    }

    @Around("cachePointCut()")
    public Object doCache(ProceedingJoinPoint joinPoint) {
        Object result = null;


        /**
         *     @MyRedisCache(keyPrefix = "user",matchValue = "#id")
         *     public User getUserById(Integer id)
         *     {
         *         return userMapper.selectByPrimaryKey(id);
         *     }
         */


        try {
            // 获得重载后的方法名
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();

            //拿到方法名后获得该方法上面配置注解标签
            MyRedisCache myRedisCache = method.getAnnotation(MyRedisCache.class);


            //拿到myRedisCache这个标签注解，获得坠恶上面配置的饿参数进行封装和调用
            String keyPrefix = myRedisCache.keyPrefix();
            String matchValue = myRedisCache.matchValue();


            //spring解析器
            SpelExpressionParser parser = new SpelExpressionParser();
            Expression expression = parser.parseExpression(matchValue);
            StandardEvaluationContext context = new StandardEvaluationContext();

            //使用反射获得方法里的形参
            Object[] args = joinPoint.getArgs();
            Parameter[] parameters = method.getParameters();
            for (int i = 0; i < parameters.length; i++) {
                System.out.println("获得方法里面的参数名和值：" + parameters[i].getName() + "/t" + args[i].toString());
                context.setVariable(parameters[i].getName(), args[i] + toString());
            }


            //通过上述拼接redis最终的key
            String key = keyPrefix + ":" + expression.getValue(context).toString();
            System.out.println("----最终拼接的形式" + key);


            //redis先查询有没有
            result = redisTemplate.opsForValue().get(key);
            if (result != null) {
                System.out.println("不打扰mysql" + result);
                return result;
            }

            //redis没有 去找mysql
            result = joinPoint.proceed();


            //mysql找到返回存储到redis一次，缓存补偿
            if (result !=null){
                System.out.println("---redis里面没有，mysql返回给redis一次，缓存补偿");
                redisTemplate.opsForValue().set(key,result);
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return result;
    }
}
